Skip to content

pm-dispatch: name the review of record for default-tier lanes, make clearing cite it, and read it in check-clause2-carriers --pair (C6) - #17349

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-17302-review-of-record
Sep 10, 2026
Merged

pm-dispatch: name the review of record for default-tier lanes, make clearing cite it, and read it in check-clause2-carriers --pair (C6)#17349
os-zhuang merged 2 commits into
mainfrom
claude/issue-17302-review-of-record

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #17302

Summary

After the tier policy landed, the rule text said the lane seat's own default-tier review "plus the gates" is the review of record for every lane but spec and skills — and named neither where that review lives nor what it must contain. This PR names it, makes every clearing of needs:contract-review cite it, and teaches check-clause2-carriers --pair to read "a review of record exists on this head" as a row of its own (C6). Three governed rule files are rewritten in place at their ceilings (812 / 60 / 151, net zero); one scripts/pm gate gains one row, one battery and one read.

The finding's evidence (quoted from #17302)

PR merged by carrier review of record
objectstack#17181 (card #15951) 2026-09-10T00:03Z (before the notice) os-steve never hung none — PR body reasons yes in prose, no line-start declaration, no card-side verdict
objectui#8921 (card #8900) 03:11Z os-zhuang hung, cleared none
objectui#8922 (no card) 03:15Z os-zhuang hung, cleared none
objectui#8926 (card #8897) 03:15Z os-zhuang hung, cleared none
objectui#8931 (card #8268) 03:28Z os-zhuang hung, cleared none

Card #15951's thread, read for this PR: a Claim:, three dispatch-failure notes, the dev's os-dev-report, a PM correction, and 「Closing by hand — PR #17181 merged as 6058cb2」 — no comment on either carrier that names a reviewer. Ask 3 is ruled on the card (the five merges are accepted under the transition) and nothing here touches them.

The review of record — the shape, spelled once

ONE comment on the PR or on its card, on the merged/landing head, carrying:

  1. a level-2 heading whose line begins ## Contract review (H51's marker in check-half-states.mjs, measured over four live dialects — the same heading may sit on a later line of a director adoption record);
  2. the reviewed head sha as a code span (H51's contractReviewHeadMatch: a 7–40 hex span that is a prefix of the PR's current head);
  3. the checklist's ①②③ as line items — derived judgments / semver / boundary flags;
  4. the independence pair, Implemented-by: and Reviewed-by:;
  5. the verdict word, PASS or FAIL.

That is the tier verdict's shape minus the tier line. Measured on the board this PR was written against, every 2026-09-09 tier verdict already satisfies it (PR #17073 comments 5597841101 and 5600239551, PR #17116 comment 5600627944, PR #17090 comment 5598904803: heading, head span, **Reviewed-by:**). A bare os-dev-report never does, nor does the implementer's own comment (the implementer is not the reviewer). ⚠️ The skills seat's own ACCEPT comments on cards #17285 / #17288 / #17308 (5613072104, 5614148443, 5614255952) carry the head and a Reviewed-by: line under a bold first line and NO heading — under this text they are not a record either, and the seat's next clearing must write the heading. The C6 self-test pins that exact shape as a control.

What the gate READS is items 1, 2 and the Reviewed-by: key line of item 4 — never the verdict word (the file's standing boundary: reading a verdict to clear a gate is 自查放行; H51 is verdict-agnostic by construction; and the live corpus already spells the word two ways — a fenced VERDICT: PASS on the 2026-09-01 board, **Verdict: PASS WITH FINDINGS** on the 2026-09-09 board — so a regex for it would be a third spelling), and never the ①②③ items (prose the seat reads). Exit 0 therefore means "a review of record exists on this head and names a reviewer", never "the review passed"; precondition ① of the landing check stays human.

Before / after, per changed line, beside the ask it implements

Every edited line is ≤ 119 bytes (the ratchet's 120-byte cap); the three files stay at 812 / 60 / 151.

Ask 1 — name the review of record (contract-review.md, twinned in SKILL.md and core-rules)

references/contract-review.md — one line was freed inside the file so the shape could take two lines:

  • :21 before 「- 重挂前先查裁决:闸门标签缺失 ⇒ 先 grep 卡评论找复审结论。」 → after 「- 重挂前先查裁决:闸门标签缺失 ⇒ 先 grep 卡评论找复审结论;get_reviews 读空 ≠ 未复审。」 (118 B; absorbs old :23)
  • old :23 「- get_reviews 读空 ≠ 未复审。」 → retired (folded into :21 above); :24–:29 renumber by −1, so the dispatch's ":28" is now :27.
  • old :29 「- 契约判断清单逐项落卡或 PR 评论,⛔ 不是散文自述。」 → new :28 「- 复核记录 = 一条评论落 PR 或卡,达档与默认档同形;散文、dev 自评、os-dev-report 恒不算。」 (118 B) + new :29 「- 同形 = ## Contract review 题头、所审 head sha 码段、①②③ 逐项、独立性对、PASS/FAIL 判词。」 (119 B)
  • :41 before 「- 落地前检三条:① 席内条款②复核 PASS 在案,即卡上的复核裁决评论(spec 席达档)。」 → after 「- 落地前检三条:① 席内条款②复核 PASS 在案,即 PR 或卡上同形的复核记录(spec 席达档)。」 (115 B)

SKILL.md :641 before 「- 交付后复核由派发席席内完成:spec 席达档自审或派该档子任务,余席默认档自审加门禁。」 → after 「- 交付后复核由派发席席内完成:spec 席达档,余席默认档加门禁;记录 = 同形评论落 PR 或卡。」 (119 B)

references/core-rules.md :123 before 「- 受管面 PR 留 draft 并向两个授权批准账户请审;无席内复核 PASS 的契约卡 ⛔ 禁止入队。」 → after 「- 受管面 PR 留 draft 并向两个授权批准账户请审;契约卡无同形复核记录 PASS ⛔ 禁止入队。」 (117 B)

Ask 2 — clearing the carrier cites it

  • contract-review.md :38 before 「- 放行 = 清标即落地:PASS ⇒ 同席同笔剥双载体,清标同笔留 provenance 评论引该 PASS。」 → after 「- 清标即落地:PASS ⇒ 同席同笔剥双载体;凡清标同笔留 provenance 评论,引记录 id 与所判 head。」 (119 B) — every clear, PASS or FAIL (:20 already clears both on FAIL), names the record comment and the head it judged.
  • contract-review.md :22 before 「- PASS + 无标 + head 未动 = 已清标不是被剥;head 后移或无结论才重挂。」 → after 「…;head 后移或无结论才重挂;清标缺引记录即半态。」 (117 B) — clearing without the citation is the half-state the sweep reads (H51/H53 are A timestamp a seat writes into GitHub must come from the clock read by the same act that writes it — make an estimated stamp unspellable (helper token and/or a report-only patrol row), after two recorded ~1h mis-estimates #17314's file and are not touched here).
  • contract-review.md :43 before 「- 该命令 0 = 双肢一致且无放宽 tell,4 = 任一不成立,3 = 环境答不了;⛔ 3 不作干净。」 → after 「- 0 = 双肢一致、无放宽 tell、head 上有记录;4 = 任一不成立;3 = 环境答不了,⛔ 不作干净。」 (115 B) — the --pair contract now includes the record.
  • SKILL.md :642 before 「- PASS ⇒ 同席剥标、ready、auto-merge;FAIL ⇒ 补丁轮;⛔ 免复核不放行。」 → after 「- PASS ⇒ 同席剥标并引记录、ready、auto-merge;FAIL ⇒ 补丁轮;⛔ 免复核不放行。」 (101 B)

Ask 3 — check-clause2-carriers --pair reads it (row C6)

scripts/pm/check-clause2-carriers.mjs:

  • needsRecordRead(pair) — owed by the COMPLETED state only (gateBindingState unchanged: declared yes, cleared on both carriers, head unmoved). A pending pair owes nothing yet; never-hung / half-bound / moved-after-clear stay C3's rows, so no fact is owned twice.
  • reviewOfRecord(pair) — reads the PR's thread and the card's; the newest ## Contract review comment naming the current head (H51's CONTRACT_REVIEW_HEADING_MARKER + contractReviewHeadMatch + latestMarkedComment, all imported from check-half-states.mjs — no cycle: that file imports nothing from this one, verified by grep) that also carries a Reviewed-by: line (C4's own AUTHORSHIP_KEY_LINES regex, key presence only — the value is C4's row). States: not-owed / unreadable / absent / unsigned / found.
  • c6NoReviewOfRecord(pair) — the FINDING row (absent, or unsigned naming the comment and the missing line); c6RecordNote(pair) — the C6-RECORD note on found, naming the comment id, thread and head span so the provenance comment can cite it.
  • gather — a fourth pass buys the PR's own thread for completed pairs only, in BOTH modes, through the existing readCardComments (a PR is an issue at /issues/N/comments), cached per PR; the offline document carries it in the same comments bag keyed by the PR number — no new field, no seventh reader method.
  • pairUnjudged — an unread PR thread (or a head sha too short to match) on a completed pair is UNJUDGED (exit 2), never a missing record.
  • renderPair — the success sentence is keyed by note CODE, not note count (the C6 note had otherwise borrowed the C2-SIBLING wording — caught by the on-time fixture run and fixed in the second commit); a found record is named in the sentence.
  • Header docblock: a C6 section, the pair-json shape, the request budget (a completed pair adds one read), the exit-2 and exit-4 rows. Self-test: one new battery (40 cases: the cost bound, the measured record on either carrier, H51's dialects, the two controls — os-dev-report and the seat's headingless ACCEPT — the unsigned state, newest-governs, the check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690 half, reporting order, and the offline bag), roster +1, floor 15 → 16; the [finding] check-clause2-carriers.mjs --pair answers C3 / exit 4 on a LEGITIMATELY cleared clause-② pair — the completed state (declaration outlives the label) is indistinguishable from the fail-open it hunts #14155 completed fixture now carries its head (9af92aa3) and its record on the PR thread, so 「the pair is CLEAN overall」 still holds and the landing check's ② still answers 0 after a legitimate clear.

Hard-4, not advisory — the decision and why. The seat's reading was "advisory until the rule text has been live for a window"; the file's own exit table decides otherwise: --pair is a predicate about THIS pair at its own landing moment, an adverse fact about it exits 4, and 「⛔ never 0-with-a-message: silence is what this whole file exists against」. C6 re-blocks no legal workflow — under the text the record precedes the clear, so a pair that followed it reads clean — and a pair cleared before the text landed owes exactly one comment (the review its seat already performed, written down) before --pair answers 0. The sweep stays report-only (rows print, exit 0), so the board-wide transition costs nothing. A window would also be the staged option the decision frame rules out by default (「过渡也从紧 —— 创业阶段不渐进」).

Offline runs on the final tree (07887a781), the same document three ways (--pair 13864 --pair-json …):

维护者速读(草稿)

改了什么 —— 三个协议文件各改几行、净零行:契约复核细则把「默认档车道的复核记录」定成一条评论(落 PR 或卡,形状 = 达档裁决同形去掉档位行),并要求每次清标的 provenance 评论引这条记录的 id 与所判 head;主文件与核心条款各改孪生行。check-clause2-carriers --pair 新增 C6 行:对已清标的条款②对子,读 PR 与卡两条线程找这条记录,没有就退出 4;找到就打印一条 NOTE 告诉席位该引哪条评论。

为什么改 —— 总监席的漏网扫描在一个窗口里量到五个 Clause-②: yes 合并没有任何复核记录,只有 dev 自己的报告。规则文本(本席上午落地的档位政策)说「车道席默认档自审加门禁就是复核记录」,却没说它住哪、长什么样,于是「清了标」和「没有审」在任何扫描里看起来一样,总监席的事后审计也没有可核对的对象。

风险与代价(含回滚) —— 代价:每次清标多写一条评论(把已经做过的复核写下来)、--pair 对已清标对子多一次读;过渡期内已清标未落地的对子跑 --pair 会红一次,补一条记录即绿;本席自己现行的 ACCEPT 评论没带 ## Contract review 题头,自下一次清标起须写成同形。风险:识别形状复用 H51 已量过的四种方言,不读裁决词、不读 ①②③;若某席写出第五种方言,C6 会报「无记录」(红而不是绿,fail-closed)。回滚:一次 revert,无发布物、无迁移。

席位意见 ——

你要做的 —— 人工合并本 draft PR(受管面 .claude/** + scripts/pm/**,席位不翻 ready、不入队、不批准)。

Acceptance notes

Gates (every command dispatch-gates.mjs --commands derived from the merge-base changeset, run on the final commit 07887a781, exits captured before any pipe; the ledger is in the os-dev-report):

  • pnpm check:pm-skill-ratchet exit 0 — 「✓ check-skill-line-ratchet: declared cross-file moves: 1, total ceilings down 9 lines.」 (812 / 60 / 151 at ceiling, headroom 0, none raised)
  • pnpm check:skill-frame-sync exit 0 — 「✓ check-skill-frame-sync: 2 copies of the decision frame are structurally isomorphic across 2 files」; SKILL.md :734–:752 md5 22f2339f0acb64cdb50c7adc9db681c3 unchanged
  • pnpm check:skill-compatibility exit 0 — 「✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 80 workspace packages」
  • pnpm check:pm-skill-id-lint exit 0 — 「✓ check-skill-id-lint: 27 file(s) clean (pattern /#[0-9]{3,}/g).」 (no issue number, model name or date in any skill file)
  • pnpm check:pm-governed-prose exit 0 — 「✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.」
  • pnpm check:nul-bytes exit 0 — 「check-nul-bytes: OK (scanned 8170 text file(s) -- 8170 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).」
  • pnpm check:pm-clause2-carriers (the self-test) exit 0 — 「✓ check-clause2-carriers self-test: 359 cases pass (… the review of record on the completed state with the two shapes that are not one …)」
  • pnpm check:pm-dispatch-gates exit 0 (710 s, detached + tail --pid) — 「✓ dispatch-gates self-test: 1674 cases pass.」
  • pnpm check:pm-governed-merges exit 0 — 「✓ check-governed-merges --self-test: 274 assertions …」 and the report-only sweep
  • node scripts/pm/check-governed-merges.mjs --test … exit 3 — 「⛔ GOVERNED — a human merge is the review record for this PR (governance: human merge IS the review record for governed surfaces — retire the per-PR ADR approval check, add a report-only post-merge audit #9495 regime). … .claude/** ×3」; scripts/pm/check-clause2-carriers.mjs reported as not on the register
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions first exit 3 PREREQUISITE NOT MET (@objectstack/formula / @objectstack/lint not built — not a measurement); built both under the verify lock (「VERDICT command-exit 0 · held the lock 165s」) and re-ran: exit 0 — 「✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 440 files / 1374 TS blocks judged clean」
  • the remaining 32 derived commands (reference-carrier-shape, changeset-no-major --base origin/main + self-test, ci-filter-parity, closing-keyword-parity, comment-mask-corpus, declaration-mirrors, scripts-symbol-anchors, self-test-wired, self-test-workflow-commands, whole-set-label-write, bare-root-worklist, governed-queue-guard, report-test-timings, agent-test-spelling, bash32-floor, changeset-gate-self-tests, cli-command-ids, cross-package-test-inputs, doc-authoring, driver-memory-census, entry-guard, parse-guard, pnpm-filter-targets, ratchet-remedy-authority, refd-timer-probe, watch-hint-literal) all exit 0
  • dispatch-gates.mjs --ran reconciliation: Run reconciliation — 43 derived, 43 run, 0 NOT-MEASURED, 0 UNRUN. (recorded as command :: exit code, exits captured before any pipe; 43 derived, 43 run)
  • Rule ⑤ (the gate script's own suite): its --self-test above; the one importer (scripts/check-changeset-no-major.mjs, readClause2Line) ran its self-test and its --base origin/main run green; lint.yml's step runs the self-test only, unchanged.
  • No package source touched ⇒ no build closure, no package tests owed.

Ceilings arithmetic: contract-review.md 60 → 60 (−1 old :23 folded into :21, −1 old :29 replaced, +2 new :28/:29); SKILL.md 812 → 812 (two lines rewritten in place); core-rules.md 151 → 151 (one line in place). Widest edited line 119 B against the 120-byte cap.

Assumptions A–D, measured

Declared deviations from the dispatch text: (1) C6 reads no verdict WORD — H51's heading + head-sha shape and the Reviewed-by: key line instead (evidence above; the rule text still names the word for the seat); (2) hard-4 rather than advisory (reasoning above); (3) the live --pair run is on this PR, whose card declares Clause-②: no — it exercises the read path and C5, not C6 (no completed-state pair was enumerated on the live board; a sweep costs the anonymous budget); the C6 reading is exercised by the three offline documents and 40 self-test cases; (4) contract-review.md :23–:29 renumber by −1.

Out of scope, filed: #17346 — C4's VERDICT: discriminator and session-only Reviewed-by: grammar match none of the four 2026-09-09 verdicts (readVerdictAuthorship(body) === null on each), so the independence carrier has no live population; C6 deliberately reads the key line only and is not blocked by it. Noted, not filed: the skills seat's own ACCEPT comments lack the heading — the rule text now names it, 承接者 = the skills seat at its next clearing.

Changeset: none owed — nothing in any package's files[] moves (.claude/** and scripts/pm/** are the fast lane); skip-changeset applied by the dev per the standing contract. Governed: draft only, never ready / enqueued / auto-merged / approved by a seat.

Generated by Claude Code


Generated by Claude Code

…--pair reads it (C6)

contract-review.md names the default-tier lanes' review of record — one comment
on the PR or its card in the tier verdict's shape minus the tier line — and
makes every clear cite it; SKILL.md and core-rules carry the twin lines.
check-clause2-carriers --pair gains C6: on a completed pair it reads the PR's
thread and the card's for that record (H51's heading + head-sha shape, plus a
Reviewed-by: line) and answers 4 when none exists.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
…e count

The C6-RECORD note made renderPair print the C2-SIBLING wording; each note
kind now speaks for itself, and a found record is named in the sentence.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
@os-justin os-justin added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 10, 2026 — with Claude
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation labels Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

维护者速读

改了什么 —— 给默认档车道的「复核记录」定一个具名的载体和形状:一条评论落在 PR 或卡上,带 ## Contract review 题头、所审 head sha、①②③ 三项逐条、Implemented-by: / Reviewed-by: 独立性对、PASS/FAIL 判词——和契约复审档裁决同形,只少一行档位。清 needs:contract-review 标签时必须引这条记录的 id 与所判 head,缺引即半态。check-clause2-carriers --pair 加一行 C6:条款②已声明、双载体已清、head 未动的对子,读 PR 与卡两条线程找这条记录,找不到 exit 4,线程读不到 exit 2(未判,不算干净)。SKILL.md 两行、契约复核细则七行、核心条款一行,全部净零。

为什么改 —— 09-10 档位改制后,默认档车道的复核不再经契约复审档,通知里说「席位自审加门禁就是复核记录」,却没说记录长什么样、放在哪。总监席一扫:一个窗口里五次条款②合并没有任何复核记录,清标和从未复核在板上分不开,事后审计也无从审起。这是本席通知的漏洞,这张卡补上。

风险与代价(含回滚) —— 不进发布包。C6 是硬 4(该文件的退出码表里,对子上任何一个不利事实都是 4,不允许 0 带口信),只在「已完成」态才触发,不会重新挡住任何合法流程;巡查行仍只报告。代价:清标多写一行引用;各席 ACCEPT 评论要带题头——本席自己之前的 ACCEPT 就没带题头(dev 在板上量了:不算记录),从本 PR 的验收评论起改用同形。回滚 = revert 一个提交。

席位意见 —— 本席按契约复审档自审通过:三个技能文件的行与两条 ask 逐句对得上;C6 的识别形状复用 H51 的题头 + head 码段加 Reviewed-by: 键行,不读判词(该文件禁止自查放行,且判词在板上有两种拼法),本席认可 dev 的选择;三份离线夹具(有记录 0 / 无记录 4 / 线程缺 2)与 40 条自测在案,本席重跑自测 359 例通过,棘轮 812/60/151 全在天花板净零,决策框架块未动。dev 顺手立了 #17346(C4 对 09-09 的裁决评论静默)——裸卡,等分诊。

你要做的 —— 人工合并本 draft PR(受管面 .claude/**)。合入后各席位的条款②复核评论要带 ## Contract review 题头。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 10, 2026 08:33
@os-zhuang
os-zhuang enabled auto-merge September 10, 2026 08:33
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit e669e5e Sep 10, 2026
40 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-17302-review-of-record branch September 10, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation needs-user-decision size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants